package com.handsome.aspect;


import com.fasterxml.jackson.databind.ObjectMapper;

import com.handsome.annotations.ActionLogAnnotation;
import com.handsome.entity.HsLog;
import com.handsome.service.LogService;
import com.handsome.utils.HttpUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

import java.util.Map;

@Component
@Aspect
public class ActionLogAspect {


    private static ObjectMapper json = new ObjectMapper();

    //注入service,用来将日志信息保存在数据库
    @Autowired
    private LogService logService;

    //定义一个切入点
    @Pointcut("execution(* com.handsome.service.impl.*.*(..))")
    private void controllerAspect() {
    }

    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("----------AOP--------------");
        //获取登录用户账户
        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.setCharacterEncoding("UTF-8");
        //获取系统ip,这里用的是我自己的工具类,可自行网上查询获取ip方法
        String ip = HttpUtil.getIpAddress(request);
        //方法通知前获取时间,为什么要记录这个时间呢？当然是用来计算模块执行时间的
        Long start = System.currentTimeMillis();
        // 拦截的实体类，就是当前正在执行的controller
        Object target = pjp.getTarget();
        // 拦截的方法名称。当前正在执行的方法
        String methodName = pjp.getSignature().getName();
        // 拦截的方法参数
        Object[] args = pjp.getArgs();
        // 拦截的放参数类型
        Signature sig = pjp.getSignature();
        // 获取参数key:val
        Map<String, Object> httpParams = HttpUtil.getHttpParams(request);
        MethodSignature msig;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Class[] parameterTypes = msig.getMethod().getParameterTypes();

        Object object;
        // 获得被拦截的方法
        Method method = null;
        try {
            method = target.getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException | SecurityException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        if (null != method) {
            // 判断是否包含自定义的注解，说明一下这里的SystemLog就是我自己自定义的注解
            if (method.isAnnotationPresent(ActionLogAnnotation.class)) {
                ActionLogAnnotation actionLogAnnotation = method.getAnnotation(ActionLogAnnotation.class);
                object = pjp.proceed();
                Long end = System.currentTimeMillis();
                //将计算好的时间保存在实体中
                String jsonObject = json.writeValueAsString(httpParams);
                HsLog hsLog = new HsLog();
                hsLog.setModule(actionLogAnnotation.module());
                hsLog.setDescription(actionLogAnnotation.description());
                hsLog.setIp(ip);
                hsLog.setParams(jsonObject);
                hsLog.setPath(request.getServletPath());
                hsLog.setTimeConsuming(Math.toIntExact(end - start));
                String username = "admin";
                hsLog.setLogType(1);
                hsLog.setUserId(1);
                hsLog.setUsername(username);
                logService.addActionLog(hsLog);
            } else {
                //没有包含注解
                object = pjp.proceed();
            }
        } else {
            //不需要拦截直接执行
            object = pjp.proceed();
        }
        return object;
    }
}
